﻿using Common;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using DBContext;
using EV.EventBus;
using Microsoft.Win32;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Interop;
using ZoneLine.Common;
using ZoneLine.Models.PackageModel;
using ZoneLine.Models.PrintModeConfig;
using ZoneLine.Models.StationConfig;
using ZoneLine.Views;
using ZoneLine.Views.converts;

namespace ZoneLine.ViewModels
{
    public class PackageUpdateViewModel : ObservableObject
    {

        #region Fileds
        private bool _scanConnect;

        private SerialPort _scanSerial;

        private Speaker _speaker;

        private readonly IModelDAL _dal;

        #endregion

        public PackageUpdateViewModel(IModelDAL modelDAL) {
            this._dal = modelDAL;
            this._speaker = Speaker.GetSpeaker();
            //this.PackageQRCode = "$P000000004040102916$V8000$L240824$Q28$O$S0$EZN1$N1";
            //this.PackageQRCode = "$P00000000404010291$V8000$L250226$Q28$O$S0$EZN1$N1";
            //this.PackageQRCode = "$P00000000404010291$V8000$L250302$Q28$O$S0$EZN1$N1";
            PackageScanConfig = _dal.GetModel<PackageScanBarConfig>(p => true);
            InitScanGun();

            MessageCenter.Subscribe("CloesQStationEnable", "", (o) =>
            {
                _scanSerial?.Close();
                return Task.CompletedTask;
            });

            MessageCenter.Subscribe("CloesHStationEnable", "", (o) =>
            {
                _scanSerial?.Close();
                return Task.CompletedTask;
            });

            MessageCenter.Subscribe(nameof(PackageUpdateView) + "Closed", "", (o) =>
            {
                _scanSerial?.Close();
                return Task.CompletedTask;
            });
        }


        #region Props

        //private string _portStatus = "关闭";

        //public string PortStatus
        //{
        //    get { return _portStatus; }
        //    set => SetProperty(ref _portStatus, value);
        //}


        private string _packageQRCode;

        public string PackageQRCode
        {
            get { return _packageQRCode; }
            set => SetProperty(ref _packageQRCode, value);
        }


        private PackageScanBarConfig _packageScanConfig;

        public PackageScanBarConfig PackageScanConfig
        {
            get { return _packageScanConfig; }
            set => SetProperty(ref _packageScanConfig, value);
        }

        private PackagePrintConfig _packageCfg;

        public PackagePrintConfig PackageCfg
        {
            get { return _packageCfg; }
            set => SetProperty(ref _packageCfg, value);
        }

        private PackagePrintConfig _newPackageCfg;

        public PackagePrintConfig NewPackageCfg
        {
            get { return _newPackageCfg; }
            set => SetProperty(ref _newPackageCfg, value);
        }

        private string _newBoxCode;

        public string NewBoxCode
        {
            get { return _newBoxCode; }
            set => SetProperty(ref _newBoxCode, value);
        }



        private ObservableCollection<PackageTempModel> _inPackageAbsLst;

        public ObservableCollection<PackageTempModel> InPackageAbsLst
        {
            get { return _inPackageAbsLst; }
            set => SetProperty(ref _inPackageAbsLst, value);
        }

        private PackageTempModel _selectedItem;

        public PackageTempModel SelectedItem
        {
            get { return _selectedItem; }
            set => SetProperty(ref _selectedItem, value);
        }


        #endregion

        #region Commands

        public RelayCommand SelectQueryCmd => new RelayCommand(GetPackageInfo);

        public RelayCommand<PackageTempModel> DeleteCmd => new RelayCommand<PackageTempModel>((obj) => {
            if (obj != null)
            {
                var res = HandyControl.Controls.MessageBox.Ask("是否确定删除当前选择的装箱数据？", "温馨提示");
                if (res == MessageBoxResult.OK)
                {
                    InPackageAbsLst.Remove(obj);
                    _dal.DeleteModel<PackageResult>(o => o.Id == obj.Id);
                }
            }
        });

        public RelayCommand SelectPackageTemplateCmd => new RelayCommand(SelectPackageTemplate); 

        public RelayCommand GenerateBoxCodeCmd => new RelayCommand(GenerateBoxCode);

        public RelayCommand PrintBoxCodeCmd => new RelayCommand(PrintBoxCode);

        public RelayCommand<string> TestAddPackageCmd => new RelayCommand<string>(arg => { /*ClearCurrentBox()*//* PieceBoxAction(arg)*/});
        #endregion


        #region Methods
        private void SelectPackageTemplate()
        {
            FileDialog dia = new OpenFileDialog();
            var rlt = dia.ShowDialog();
            string path = string.Empty;
            if (rlt.HasValue && rlt.Value)
            {
                PackageCfg.TemplatePath = dia.FileName;
            }
        }

        private void GetPackageInfo() {

            if (!string.IsNullOrEmpty(PackageQRCode))
            {
                //加载箱码初始信息
                var packageConfig = _dal.GetModel<PackagePrintConfig>(p => true);
                if (packageConfig == null)
                {
                    _dal.AddModel(new PackagePrintConfig());
                    packageConfig = new PackagePrintConfig();
                }
                PackageCfg = packageConfig;

                //加载产品信息
                var packageResultList = _dal.GetModelList<PackageResult>(o => o.BoxCode == PackageQRCode).ToList();
                InPackageAbsLst = new ObservableCollection<PackageTempModel>();
                foreach (var item in packageResultList)
                {
                    var temp = new PackageTempModel()
                    {
                        Id = item.Id,
                        AbsCode = item.AbsCode,
                        BoxCode = item.BoxCode,
                        Brand = item.Brand,
                        Code = item.Code,
                        LeftRight = item.LeftRight,
                        PackageTime = item.PackageTime,
                        PrintTime = item.PrintTime,
                    };
                    InPackageAbsLst.Add(temp);
                }

                //解析当前产品的箱码信息
                if (packageResultList != null && packageResultList.Count > 0)
                {
                    var firstItem = packageResultList.FirstOrDefault();
                    var boxInfo = firstItem.BoxCode.Split('$').ToList();
                    PackageCfg.MaterialCode = boxInfo[1]?.ToString().Replace("P", "");
                    PackageCfg.BatchCode = boxInfo[3]?.ToString().Replace("R", "").Replace("L", "");
                    PackageCfg.PackageCount = Convert.ToInt32(boxInfo[4]?.ToString().Replace("Q", ""));
                    PackageCfg.WorkShop = boxInfo[7]?.ToString().Replace("E", "");
                    PackageCfg.BoxNum = Convert.ToInt32(boxInfo[8]?.ToString().Replace("N", ""));


                    var modelConvert = new ModelConvert();
                    var modelStr = modelConvert.Convert(Cache.Model, null, "", null);
                    var workDirecitionConvert = new WorkDirecitionConvert();
                    var workDirecitionStr = workDirecitionConvert.Convert(Cache.WorkDirection, null, "", null);
                    PackageCfg.ProductInfo = string.Format(packageConfig.ProductInfo, modelStr, Cache.CurrentProductType, (Cache.IsHopStaion ? "后" : Cache.IsQopStaion ? "前" : ""), workDirecitionStr);

                    //物料编码
                    packageConfig.MaterialCode = SysCfg.GetBoxCodeMaterialCode(Cache.IsQopStaion ? 1 : Cache.IsHopStaion ? 2 : 0, Cache.CurrentProductType, Cache.WorkDirection);
                }

            }
            else {
                HandyControl.Controls.MessageBox.Error("箱码不能为空！","温馨提示");
            }
        }

        private void GenerateBoxCode()
        {
            if (InPackageAbsLst == null || InPackageAbsLst.Count == 0)
            {
                HandyControl.Controls.MessageBox.Error("生成失败，当前未进行产品录入！", "温馨提示");
                MessageCenter.PublishAsync(nameof(PackageUpdateViewModel), "装箱信息:箱码生成失败，当前未进行产品录入！");
                NewBoxCode = "";
                return;
            }

            if (InPackageAbsLst.Count != PackageCfg.PackageCount)
            {
                HandyControl.Controls.MessageBox.Error("装箱失败，当前装入产品数量与设定装箱数量不符！", "温馨提示");
                MessageCenter.PublishAsync(nameof(PackageUpdateViewModel), "装箱信息:箱码生成失败，当前装入产品数量与设定装箱数量不符！");
                NewBoxCode = "";
                return;
            }

            NewBoxCode = $"$P{PackageCfg.MaterialCode}$V8000$L{PackageCfg.BatchCode}$Q{PackageCfg.PackageCount}$O$S0$E{PackageCfg.WorkShop}$N{PackageCfg.BoxNum}";
            var codeTemp = $"$P{PackageCfg.MaterialCode}$V8000$L{PackageCfg.BatchCode}$Q{PackageCfg.PackageCount}$O$S0$E{PackageCfg.WorkShop}$N{PackageCfg.BoxNum}";
            MessageCenter.PublishAsync(nameof(PackageUpdateViewModel), $"装箱信息:箱码生成成功，当前信息生成的箱码是【{codeTemp}】");
        }

        private int _scanLinkCount = 0;
        /// <summary>
        /// 初始化扫码枪
        /// </summary>
        private void InitScanGun()
        {
            Task.Run(() =>
            {
                //while (PortStatus!="打开")
                while (!_scanConnect)
                {
                    try
                    {
                        _scanLinkCount++;
                        //PortStatus = "打开中";
                        //MessageCenter.PublishAsync(nameof(PackageUpdateViewModel), $"正在尝试第{_scanLinkCount}次连接扫码枪.");
                        if (_scanSerial == null)
                        {
                            _scanSerial = new SerialPort();
                            _scanSerial.PortName = PackageScanConfig.Port;
                            _scanSerial.BaudRate = 115200;
                            _scanSerial.DataBits = 8;
                            _scanSerial.StopBits = StopBits.One;
                            _scanSerial.Parity = Parity.None;
                            _scanSerial.DataReceived += ScanSerial_DataReceived;
                        }
                        _scanSerial.Close();
                        _scanSerial.Open();
                        if (_scanSerial.IsOpen)
                        {
                            _scanConnect = true;
                            //MessageCenter.PublishAsync(nameof(PackageUpdateViewModel), "扫码枪连接成功.");
                            break;
                        }
                    }
                    catch (Exception ex)
                    {
                        //PortStatus = "打开失败,重试中";
                        //MessageCenter.PublishAsync(nameof(PackageUpdateViewModel), $"扫码枪连接失败,重试中...");
                        Logger.Log.Error($"扫码枪连接失败!");
                    }

                    if (_scanLinkCount >= 50)
                    {
                        MessageCenter.PublishAsync(nameof(PackageUpdateViewModel), $"扫码枪连接失败,已重试{_scanLinkCount}次,取消连接.");
                        Logger.Log.Error($"扫码枪连接失败,已重试{_scanLinkCount}次,取消连接.");
                        break;
                    }

                    Thread.Sleep(1000);
                }
            });
        }

        private int count;
        /// <summary>
        /// 扫码枪接收事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ScanSerial_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            Thread.Sleep(200);

            var lenght = _scanSerial.BytesToRead;

            var bytes = new byte[lenght];
            _scanSerial.Read(bytes, 0, lenght);
            var str = Encoding.UTF8.GetString(bytes).Replace("\n", "").Replace("\r", "");
            count++;
            MessageCenter.PublishAsync(nameof(PackageUpdateViewModel), $"扫码枪收到第{count}个条码:{str}");
            //区分产品码和箱码
            if (str.Contains("$"))//箱码二维码
            {
                this.PackageQRCode = str;
            }
            else if (str.Contains("/"))//产品条码
            {
                PieceBoxAction(str);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="code"></param>
        private void PieceBoxAction(string code)
        {
            try
            {
                if (InPackageAbsLst.Count == PackageCfg.PackageCount)
                {
                    MessageCenter.PublishAsync(nameof(PackageUpdateViewModel), $"装箱信息:装箱失败，已达到设定的装箱数量，请手动点击生成箱码！");
                    return;
                }

                var (hasWorkRlt, printRlt) = CheckPieceHasWorked(code);
                if (!hasWorkRlt)
                {
                    MessageCenter.PublishAsync(nameof(Speaker), "装箱失败，工件未在生产线加工");
                    MessageCenter.PublishAsync(nameof(PackageUpdateViewModel), "装箱信息:装箱失败，工件未在生产线加工或在生产线加工NG");
                    return;
                }

                //var (hasBoxInTemp, boxTemp) = CheckPieceBoxInTemp(code);
                //if (hasBoxInTemp)
                //{
                //    MessageCenter.PublishAsync(nameof(Speaker), "装箱失败，工件已在当前箱");
                //    MessageCenter.PublishAsync(nameof(PackageUpdateViewModel), $"装箱信息:装箱失败，工件已在当前箱装箱过程中，箱码:{boxTemp.BoxCode}");
                //    return;
                //}

                var (hasBoxed, boxed) = CheckPieceBoxed(code);
                if (hasBoxed)
                {
                    MessageCenter.PublishAsync(nameof(Speaker), "装箱失败，工件已被装箱");
                    MessageCenter.PublishAsync(nameof(PackageUpdateViewModel), $"装箱信息:装箱失败，工件已被装箱，箱码:{boxed.BoxCode}");
                    return;
                }

                var isSameBrand = CheckIsCurrentBrand(printRlt);
                if (!isSameBrand)
                {
                    MessageCenter.PublishAsync(nameof(Speaker), "装箱失败，型号不同");
                    MessageCenter.PublishAsync(nameof(PackageUpdateViewModel), $"装箱信息:装箱失败，工件和箱子中的型号不同，当前工件型号:{printRlt.Brand}");
                    return;
                }
                var isSameLs = CheckIsSameLR(printRlt);
                if (!isSameLs)
                {
                    MessageCenter.PublishAsync(nameof(Speaker), "装箱失败，左右不同");
                    MessageCenter.PublishAsync(nameof(PackageUpdateViewModel), $"装箱信息:装箱失败，工件和箱子中的左右不同，当前工件左右是:{(printRlt.LeftRight == 1 ? "左" : "右")}");
                    return;
                }

                var pieceBoxRlt = new PackageResult()
                {
                    AbsCode = printRlt.AbsCode,
                    Brand = printRlt.Brand,
                    LeftRight = printRlt.LeftRight,
                    PrintTime = printRlt.PrintTime,
                    Code = printRlt.Code,
                };
                if (pieceBoxRlt != null)
                {
                    pieceBoxRlt.BoxCode = PackageQRCode;//直接用原箱码，如果新箱码与原箱码不一致，则打印成功之后直接跟新为新的箱码
                    pieceBoxRlt.PackageTime = DateTime.Now;
                    var recordRlt = _dal.AddModel(pieceBoxRlt);//添加到数据库
                    if (recordRlt)
                    {
                        SelectQueryCmd.Execute(null);
                        var count = InPackageAbsLst.Count;
                        MessageCenter.PublishAsync(nameof(Speaker), $"装箱成功，第{count}个产品");
                        MessageCenter.PublishAsync(nameof(PackageUpdateViewModel), $"装箱信息:装箱成功，这是该箱子的第{count}个产品");
                        if (InPackageAbsLst.Count == PackageCfg.PackageCount)
                        {
                            MessageCenter.PublishAsync(nameof(Speaker), $"产品已够数，开始自动打印！");
                            MessageCenter.PublishAsync(nameof(PackageUpdateViewModel), $"装箱信息:装箱成功,设定箱量产品已够数，开始自动打印！");

                            GenerateBoxCode();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageCenter.PublishAsync(nameof(Speaker), "装箱异常");
                MessageCenter.PublishAsync(nameof(PackageUpdateViewModel), $"装箱信息:装箱异常{ex.Message}");
            }
        }

        private void PrintBoxCode()
        {

           var  resAsk = HandyControl.Controls.MessageBox.Ask("请确认打印信息是否无误？");
            if (resAsk != MessageBoxResult.OK) return;

            //编码 BM_N7
            //产品描述 CPMS_N7
            //批号 PH_N7
            //数量 SL_N7
            //单位 DW_N7
            //箱号 XH_N7
            //二维码 EWM_N7

            if (string.IsNullOrEmpty(NewBoxCode))
            {
                HandyControl.Controls.MessageBox.Error("请先生成箱码再打印！");
                return;
            }
            string CTPM = string.Empty;
            switch (Cache.Model.ToString())
            {
                case "LX":
                    if (((int)Cache.WorkDirection).Equals(1))
                    {
                        CTPM = _dal.GetModel<LXQC_Config>(g => g.ProductType.Equals(Cache.CurrentProductType)).PartNoL;
                    }
                    else
                    {
                        CTPM = _dal.GetModel<LXQC_Config>(g => g.ProductType.Equals(Cache.CurrentProductType)).PartNoR;
                    }
                    break;

                case "SQ":
                    if (((int)Cache.WorkDirection).Equals(1))
                    {
                        CTPM = _dal.GetModel<SQQC_Config>(g => g.ProductType.Equals(Cache.CurrentProductType)).PartIdentificationCode;
                    }
                    else
                    {
                        CTPM = _dal.GetModel<SQQC_Config>(g => g.ProductType.Equals(Cache.CurrentProductType)).PartIdentificationCode;
                    }
                    break;

                case "BQKH":
                    if (((int)Cache.WorkDirection).Equals(1))
                    {
                        CTPM = _dal.GetModel<BQQC_KH_Config>(g => g.ProductType.Equals(Cache.CurrentProductType)).PartNumber;
                    }
                    else
                    {
                        CTPM = _dal.GetModel<BQQC_KH_Config>(g => g.ProductType.Equals(Cache.CurrentProductType)).PartNumber;
                    }
                    break;

                case "BQLH":
                    if (((int)Cache.WorkDirection).Equals(1))
                    {
                        CTPM = _dal.GetModel<BQQC_LH_Config>(g => g.ProductType.Equals(Cache.CurrentProductType)).PartNo;
                    }
                    else
                    {
                        CTPM = _dal.GetModel<BQQC_LH_Config>(g => g.ProductType.Equals(Cache.CurrentProductType)).PartNo;
                    }
                    break;

                case "WL":
                    if (((int)Cache.WorkDirection).Equals(1))
                    {
                        CTPM = _dal.GetModel<WLQCConfig>(g => g.ProductType.Equals(Cache.CurrentProductType)).PartNo;
                    }
                    else
                    {
                        CTPM = _dal.GetModel<WLQCConfig>(g => g.ProductType.Equals(Cache.CurrentProductType)).PartNo;
                    }
                    break;

                default:
                    break;
            }
            Task.Run(() =>
            {
                try
                {
                    //BoxCode = $"$P{PackageCfg.MaterialCode}$V8000$L{PackageCfg.BatchCode}$Q{PackageCfg.PackageCount}$O$S0$E{PackageCfg.WorkShop}$N{PackageCfg.BoxNum}";
                    MessageCenter.PublishAsync(nameof(PackageUpdateViewModel), $"开始打印箱码{NewBoxCode}");
                    var paras = new Dictionary<string, string>() { { "Code", NewBoxCode } };
                    paras.Add("CPTM_N7", CTPM);
                    paras.Add("BM_N7", PackageCfg.MaterialCode);
                    paras.Add("CPMS_N7", PackageCfg.ProductInfo);
                    paras.Add("PH_N7", PackageCfg.BatchCode);
                    paras.Add("SL_N7", PackageCfg.PackageCount.ToString());
                    paras.Add("DW_N7", PackageCfg.Unit);
                    paras.Add("XH_N7", PackageCfg.BoxNum.ToString());
                    paras.Add("EWM_N7", NewBoxCode);
                    PrinterHelper.PrinterLabel(PackageCfg.TemplatePath, PackageScanConfig.Printer, paras);
                    MessageCenter.PublishAsync(nameof(PackageUpdateViewModel), $"箱码打印成功");
                    //更新数据
                    UpdatePackageResult();
                    //清除数据
                    ClearCurrentBox();
                }
                catch (Exception ex)
                {
                    MessageCenter.PublishAsync(nameof(PackageUpdateViewModel), $"箱码打印失败:{ex.Message}");
                    Logger.Log.Error(ex, "打印箱码失败");
                }
            });
        }

        /// <summary>
        /// 检测条码工件是否工作加工并加工完成
        /// </summary>
        private (bool, AbsPrintResult) CheckPieceHasWorked(string code)
        {
            var printResult = _dal.GetModel<AbsPrintResult>(p => p.Code == code);
            if (printResult == null)
            {
                return (false, null);
            }
            else
            {
                return (true, printResult);
            }
        }

        /// <summary>
        /// 检查该条码的工件是否已经在装箱中间表
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        //private (bool, PackageTempModel) CheckPieceBoxInTemp(string code)
        //{
        //    var packageTemp = InPackageAbsLst.Where(o => o.Code == code).FirstOrDefault();
        //    return (packageTemp != null, packageTemp);
        //}

        /// <summary>
        /// 检查该条码的工件是否已经装箱成功
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        private (bool, PackageTempModel) CheckPieceBoxed(string code)
        {
            var packageTemp = _dal.GetModel<PackageResult>(p => p.Code == code);
            return (packageTemp != null, packageTemp);
        }

        /// <summary>
        /// 根据条码检测当前这个工件和原有的是不是一个品牌
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        private bool CheckIsCurrentBrand(AbsPrintResult abs)
        {
            return InPackageAbsLst.Where(o => o.Brand != abs.Brand).Count() == 0;
        }

        /// <summary>
        /// 根据条码检测当前这个工件和原有的是不是左右一样
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        private bool CheckIsSameLR(AbsPrintResult abs)
        {
            return abs.Brand == Cache.Model.ToString() && (int)Cache.WorkDirection == abs.LeftRight;
        }

        private void UpdatePackageResult() {

            if (PackageQRCode != NewBoxCode) //更新为新的箱码
            {
                foreach (var item in InPackageAbsLst)
                {
                    var res = _dal.UpdateModel<PackageResult>(o => o.Id == item.Id, p => new PackageResult { BoxCode = NewBoxCode });
                    Logger.Log.Warn($"箱码更新结果：{res}，参数：{JsonConvert.SerializeObject(item)},OldBoxCode：{PackageQRCode},NewBoxCode：{NewBoxCode}");
                }
            }
        }

        private void ClearCurrentBox()
        {
            App.Current.Dispatcher.Invoke(() =>
            {
                //PackageQRCode = "";
                InPackageAbsLst.Clear();
                NewBoxCode = "";
                //PackageCfg = default;
            });
        }
        #endregion

    }
}
